#ifndef JM_LOG_H_JM_20130121
#define JM_LOG_H_JM_20130121

#include "Logger.h"

#define JM_ADD_LOG_APPENDER(app, format, config) static jmlib::LogAppenderRegistrator jmlib_log_appender_##app(#app, new app(format, config));

#define JM_SET_ALL_LOGGER_ACTIVE static jmlib::LoggerActivatorByName jmlib_all_logger_activator("", "");
#define JM_SET_LOGGER_ACTIVE(loggerId) static jmlib::LoggerActivatorByName jmlib_logger_##loggerId(#loggerId, "");
#define JM_SET_LOGGER_ACTIVE_BY_PREFIX(loggerIdPrefix) static jmlib::LoggerActivatorByNamePrefix jmlib_logger_by_prefix_##loggerIdPrefix(#loggerIdPrefix, "");

#define JM_SET_ALL_LOGGER_ACTIVE_ON_APPENDER(appName) static jmlib::LoggerActivatorByName jmlib_all_logger_activator("", #appName);
#define JM_SET_LOGGER_ACTIVE_ON_APPENDER(loggerId, appName) static jmlib::LoggerActivatorByName jmlib_logger_##loggerId(#loggerId, #appName);
#define JM_SET_LOGGER_ACTIVE_BY_PREFIX_ON_APPENDER(loggerIdPrefix, appName) static jmlib::LoggerActivatorByNamePrefix jmlib_logger_by_prefix_##loggerIdPrefix(#loggerIdPrefix, #appName);

//#define JM_USE_LOGGER(loggerId) struct jmlib__Logger: public jmlib::Logger { jmlib__Logger(): jmlib::Logger(#loggerId) { } }; mutable jmlib__Logger jmlib_log_;
//#define JM_USE_EXPLICIT_LOGGER(loggerId) struct jmlib__Logger__##loggerId: public jmlib::Logger { jmlib__Logger__##loggerId() : jmlib::Logger(#loggerId) { } }; mutable jmlib__Logger__##loggerId jmlib_log_##loggerId;

#define JM_USE_LOGGER(loggerId) struct jmlib__Logger { mutable jmlib::Logger logger; jmlib__Logger(): logger(#loggerId) { } }; jmlib__Logger jmlib_log_;
#define JM_USE_EXPLICIT_LOGGER(loggerId) struct jmlib__Logger__##loggerId {mutable jmlib::Logger logger; jmlib__Logger__##loggerId() : logger(#loggerId) { } }; jmlib__Logger__##loggerId jmlib_log_##loggerId;


//#define JM_USE_LOGGER_2(loggerId) struct jmlib__Logger: public jmlib::Logger { jmlib__Logger(): jmlib::Logger(#loggerId) { } }; jmlib__Logger jmlib_log_;
//#define JM_USE_EXPLICIT_LOGGER_2(loggerId) struct jmlib__Logger__##loggerId: public jmlib::Logger { jmlib__Logger__##loggerId() : jmlib::Logger(#loggerId) { } }; jmlib__Logger__##loggerId jmlib_log_##loggerId;


#ifndef JM_DISABLE_LOG_INFO
#define JM_ENABLE_LOG_INFO
#endif

#ifndef JM_DISABLE_LOG_WARN
#define JM_ENABLE_LOG_WARN
#endif

#ifndef JM_DISABLE_LOG_ERROR
#define JM_ENABLE_LOG_ERROR
#endif

#define JM_DEFAULT_LOG_SPECIFICATOR
#define JM_TRACE_LOG_LEVEL "TRACE"
#define JM_DEBUG_LOG_LEVEL "DEBUG"
#define JM_INFO_LOG_LEVEL  "INFO"
#define JM_WARN_LOG_LEVEL  "WARN"
#define JM_ERROR_LOG_LEVEL "ERROR"

#ifdef JM_ENABLE_LOG_TRACE
#define JM_LOG_TRACE_EXPLICIT(spec, m) JM_INNER_LOG(jmlib_log_##spec, JM_TRACE_LOG_LEVEL, m)
#define JM_LOG_TRACE(m) JM_INNER_LOG(jmlib_log_, JM_TRACE_LOG_LEVEL, m)
#else
#define JM_LOG_TRACE_EXPLICIT(spec, m)
#define JM_LOG_TRACE(m)
#endif

#ifdef JM_ENABLE_LOG_DEBUG
#define JM_LOG_DEBUG_EXPLICIT(spec, m) JM_INNER_LOG(jmlib_log_##spec, JM_DEBUG_LOG_LEVEL, m)
#define JM_LOG_DEBUG(m) JM_INNER_LOG(jmlib_log_, JM_DEBUG_LOG_LEVEL, m)
#else
#define JM_LOG_DEBUG_EXPLICIT(spec, m)
#define JM_LOG_DEBUG(m)
#endif

#ifdef JM_ENABLE_LOG_INFO
#define JM_LOG_INFO_EXPLICIT(spec, m) JM_INNER_LOG(jmlib_log_##spec, JM_INFO_LOG_LEVEL, m)
#define JM_LOG_INFO(m) JM_INNER_LOG(jmlib_log_, JM_INFO_LOG_LEVEL, m)
#else
#define JM_LOG_INFO_EXPLICIT(spec, m)
#define JM_LOG_INFO(m)
#endif

#ifdef JM_ENABLE_LOG_WARN
#define JM_LOG_WARN_EXPLICIT(spec, m) JM_INNER_LOG(jmlib_log_##spec, JM_WARN_LOG_LEVEL, m)
#define JM_LOG_WARN(m) JM_INNER_LOG(jmlib_log_, JM_WARN_LOG_LEVEL, m)
#else
#define JM_LOG_WARN_EXPLICIT(spec, m)
#define JM_LOG_WARN(m)
#endif

#ifdef JM_ENABLE_LOG_ERROR
#define JM_LOG_ERROR_EXPLICIT(spec, m) JM_INNER_LOG(jmlib_log_##spec, JM_ERROR_LOG_LEVEL, m)
#define JM_LOG_ERROR(m) JM_INNER_LOG(jmlib_log_, JM_ERROR_LOG_LEVEL, m)
#else
#define JM_LOG_ERROR_EXPLICIT(spec, m)
#define JM_LOG_ERROR(m)
#endif

#ifdef JM_ENABLE_LOG_SYNCHRONIZATION
#define JM_INNER_LOG(log, level, message) for (jmlib::LoggerRegister::LogAppenderSet::iterator it = log.logger.getLogAppenderBegin(); it != log.logger.getLogAppenderEnd(); ++it) { (*it)->lockLog(); (*it)->beforeLogging(log.logger.getId(), level, __FUNCTION__, __LINE__, (int)&log); (*it)->getOutputStream() << message << std::endl; (*it)->afterLogging(); (*it)->unlockLog();}
#else
#define JM_INNER_LOG(log, level, message) for (jmlib::LoggerRegister::LogAppenderSet::iterator it = log.logger.getLogAppenderBegin(); it != log.logger.getLogAppenderEnd(); ++it) { (*it)->beforeLogging(log.logger.getId(), level, __FUNCTION__, __LINE__, (int)&log); (*it)->getOutputStream() << message << std::endl; (*it)->afterLogging(); }
#endif

#endif
